﻿using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

namespace Elentok.Common.Wpf.Services
{
  /// <summary>
  /// Defines the keybinding service
  /// </summary>
  public interface IKeybindingService
  {
    /// <summary>
    /// Registers an element as "<paramref name="elementName"/>"
    /// (so commands can register to this element)
    /// </summary>
    /// <param name="elementName"></param>
    /// <param name="element"></param>
    void RegisterElement(string elementName, UIElement element);

    /// <summary>
    /// Registers a command that will run when "<paramref name="key"/>" is 
    /// pressed in the element named "<paramref name="elementName"/>".
    /// </summary>
    /// <param name="elementName"></param>
    /// <param name="command"></param>
    /// <param name="key"></param>
    void RegisterCommand(string elementName, ICommand command, KeyGesture key);
  }

  /// <summary>
  /// The default implementation of the keybinding service
  /// </summary>
  public class KeybindingService : IKeybindingService
  {
    private Dictionary<string, UIElement> elements = new Dictionary<string, UIElement>();
    private Dictionary<string, InputBindingCollection> temporaryBindings = new Dictionary<string, InputBindingCollection>();

    /// <summary>
    /// Registers an element as "<paramref name="elementName"/>"
    /// (so commands can register to this element)
    /// </summary>
    /// <param name="elementName"></param>
    /// <param name="element"></param>
    public void RegisterElement(string elementName, UIElement element)
    {
      this.elements.Add(elementName, element);

      InputBindingCollection elementTemporaryBindings = null;
      if (this.temporaryBindings.TryGetValue(elementName, out elementTemporaryBindings))
      {
        element.InputBindings.AddRange(elementTemporaryBindings);
        this.temporaryBindings.Remove(elementName);
      }
    }

    /// <summary>
    /// Registers a command that will run when "<paramref name="key"/>" is 
    /// pressed in the element named "<paramref name="elementName"/>".
    /// </summary>
    /// <param name="elementName"></param>
    /// <param name="command"></param>
    /// <param name="key"></param>
    public void RegisterCommand(string elementName, ICommand command, KeyGesture key)
    {
      InputBindingCollection inputBindings = null;
      UIElement element = null;
      if (this.elements.TryGetValue(elementName, out element))
        inputBindings = element.InputBindings;
      else if (!this.temporaryBindings.TryGetValue(elementName, out inputBindings))
      {
        inputBindings = new InputBindingCollection();
        this.temporaryBindings.Add(elementName, inputBindings);
      }

      inputBindings.Add(new InputBinding(command, key));
    }
  }

}
